/**
 * GB28181服务监听程序
 */
const parseString = require('xml2js').parseString;
const sip         = require('sip');
const log4js      = require('../data/log');
const logger      = log4js.getLogger('sip');
const constants   = require('../data/constants');

// 命令都放在这里
const command     = require('./command');

const deviceModel = require('../model/device');
const channelModel= require('../model/channel');
const format      = require('string-format');
// 编码转换
const iconv = require('iconv-lite');

/**
 * SIP服务端
 */
const sipServer={
  running: false,
  sipSetting: null,
  stop: function(){
    if(this.running){
      sip.stop();
    }
  },
  // 重启GB28181 服务
  restart: function(option){
    this.sipSetting=option;
    if(!sipServer.running){
      sipServer.start(option);
    }
  },
  /**
   * 启动 sip 服务端
   */ 
  start: function(option){
    logger.info('启动GB28181的参数:',option);
    this.sipSetting=option;
    command.config(this.sipSetting);
    let me = sipServer;

    sip.start({
      port: this.sipSetting.sip_command_port,
      udp:  constants.sip.udp,
      tcp:  constants.sip.tcp,
      logger: { 
        send: function(message, address) { 
          // let str=format('{status} {headers.cseq.method} from={headers.from.uri} to={headers.to.uri} cseq={headers.cseq.seq}',message);
          // logger.info("send:" ,str, 'callid=' + message.headers["call-id"] ); 
          if(message.headers.via.length>1){
            logger.info('---send and via 1---',message,message.headers.via[1]);
          }else{
            logger.info('---send and via 0---',message,message.headers.via[0]);
          }
        },
        recv: function(rq, address) {
          // let str = format('{method} {headers.cseq.method} from={headers.from.uri} to={headers.to.uri} cseq={headers.cseq.seq}',rq);
          // logger.info("recv:",str,'callid=' + rq.headers["call-id"] ); 
          if(rq.headers.via.length>1){
            logger.info('===receive and via 1===',rq,rq.headers.via[1]);
          }else{
            logger.info('===receive and via 0===',rq,rq.headers.via[0]);
          }
       
          // 不知道为什么有些消息在下面回调怎么取不到，临时放在这里处理
          if(!rq.method){
            switch(rq.status){
              case 100:
                logger.info('retry');
                break;
              case 200:
                if(rq.headers.cseq.method=='INVITE'){
                  // 回复ack
                  let inviteAck = command.inviteAck(rq);
                  sip.send(inviteAck);
                }
                break;
              case 400:
                logger.error('bad request', rq);
                break;
            }
          }
        }
      }
    },
    function(rq) {
      let receiveUri  = sip.parseUri(rq.headers.from.uri);
      let deviceid    = receiveUri.user;
      me.loadDevice(deviceid, function(obj){
        if(obj){
          me.dataHandler(rq, deviceid, me.sipSetting.sip_command_password, me.sipSetting.server_realm);          
        }
      });
    });
    command.sip = sip;
  },
  /**
   * 从数据库加载设备信息,如果没加载到就赋初始值
   * @param {*} deviceid 设备号
   * @param {*} callback 回调函数
   */
  loadDevice: function(deviceid, callback){
    let me = this;
    if(!me.sipSetting){
      return;
    }
    if(constants.registry[deviceid]){
      callback(constants.registry[deviceid]);
    }else{
       // 从数据库加载
       deviceModel.getDeviceByDeviceId(deviceid,(obj)=>{
        constants.registry[deviceid] ={
          online  : false,
          session : {realm:me.sipSetting.server_realm},
          password: me.sipSetting.sip_command_password,
          sumnum  : 1,
          version : constants.sip.version
        };
        if(obj && obj.length>0){
          constants.registry[deviceid] = Object.assign(constants.registry[deviceid], obj[0]);
        }
        callback(constants.registry[deviceid]);
      });
    }
  },
  // 消息分流处理
  dataHandler:function(rq, deviceid, sip_command_password, server_realm){
    if(!rq.method){
      // method为空的放到logger的recv里处理了
      return;
    }
    let uriObj    = command.analysisUri(rq);
    if(rq.method ==='REGISTER') {
      if(!constants.registry[deviceid]){
        // 生成用户信息
        constants.registry[deviceid] = {
          password  : sip_command_password,
          online    : false,
          deviceid  : deviceid,
          session   : {
            realm   : server_realm
          },
          sip_command_host  : uriObj.sip_command_host,
          sip_command_port  : uriObj.sip_command_port,
          play      : false, // 是否在播放     
          uri       : uriObj.uri,
          protocol  : rq.headers.via[0].protocol ? rq.headers.via[0].protocol : 'UDP'
        };
      }
      if(!constants.registry[deviceid].deviceid){
        constants.registry[deviceid].deviceid=deviceid;
      }
      // 回复注册请求
      let registerAck = command.registerAck(rq);
      if(registerAck.headers.via[0] ){
        constants.registry[deviceid].via0 = Object.assign({},registerAck.headers.via[0]);
        // 带内网设备需要端口转发
        if(constants.registry[deviceid].via0.params && constants.registry[deviceid].via0.params.received){
          constants.registry[deviceid].sip_command_host = constants.registry[deviceid].via0.params.received;
          constants.registry[deviceid].sip_command_port = constants.registry[deviceid].via0.params.rport;
        }
      }else{
        constants.registry[deviceid].via0 = null;
        constants.registry[deviceid].sip_command_host = uriObj.sip_command_host;
        constants.registry[deviceid].sip_command_port = uriObj.sip_command_port;
      }
      sip.send(registerAck);

      constants.registry[deviceid].last_heart=(new Date()).getTime();
      // 如果通过校验
      if(registerAck.status==200){
        constants.registry[deviceid].contact = rq.headers.contact;
        constants.registry[deviceid].online=true;

        // 记录到数据库
        deviceModel.updateOnline(deviceid,1,()=>{
          let catalogCmd = command.catalog(constants.registry[deviceid]);
          // 发送更新目录命令
          sip.send(catalogCmd);
          // 更新额外信息
          deviceModel.update({
            deviceid  : deviceid,
            sip_command_host : constants.registry[deviceid].sip_command_host ,
            sip_command_port : constants.registry[deviceid].sip_command_port
          },null);
        });
      }
    }

    else if(rq.method==='MESSAGE'){
      if(!constants.registry[deviceid] || !constants.registry[deviceid].online){
        logger.warn("需要重新注册", deviceid);
      }else{
        if(!rq.content){
          logger.warn('rq.content为空，无法解析，目前遇到的情况是不支持Catalog，所以这里创建子通道');
          constants.registry[deviceid].sumnum='1';
          let temp1={
            Name        : [''],
            Manufacturer: [''],
            Model       : [''],
            Owner       : [''],
            CivilCode   : [''],
            Address     : [''],
            RegisterWay : ['1'],
            Secrecy     : ['0'],
            ParentID    : [deviceid],
            DeviceID    : [deviceid]
          };

          let channelId=deviceid;
          // 临时调试
          if(['34020000001320000371','34020000001320000369','34020000001320000374'].indexOf(deviceid)>-1){
            channelId = '34020000001320000001';
          }
          if(!constants.registry[deviceid].channels){
            constants.registry[deviceid].channels={};
         

            // 子通道赋初值
            constants.registry[deviceid].channels[channelId]=Object.assign({},constants.registry[deviceid]);
            delete constants.registry[deviceid].channels[channelId]['channels'];
            delete constants.registry[deviceid].channels[channelId]['sip_command_host'];
            delete constants.registry[deviceid].channels[channelId]['sip_command_port'];

            constants.registry[deviceid].channels[channelId].deviceid=channelId;
            if(!constants.registry[deviceid].channels[channelId].uri){
              logger.warn(constants.registry[deviceid].channels[channelId]);
            }else{
              // constants.registry[deviceid].channels[channelId].uri=constants.registry[deviceid].channels[channelId].uri;
            }
            constants.registry[deviceid].channels[channelId].parentid=deviceid;

            channelModel.updateDeviceInfo(temp1);
          }
          return;
        }
        // 收到其它消息
        parseString(rq.content,(err,result)=>{
          if(result.Notify){
            let CmdType = result.Notify.CmdType[0];
            switch(CmdType){
              case 'Keepalive':
                // 心跳
                // 对指定device更新状态
                logger.info(constants.registry[deviceid]);
                deviceModel.updateOnline(deviceid,1,()=>{
                  channelModel.updateOnline(deviceid,result.Notify.DeviceID,1).then(()=>{
                    let alive = command.keepalive(rq);
                    sip.send(alive);
                  }).catch((e)=>{
                    logger.error(e);
                  });
                });
                
                  
                break;
              case 'Catalog':
                // 定时刷新catalog状态
                let deviceIds = result.Notify.DeviceID;
                // deviceModel.updateOnline(deviceid,1,()=>{});
                for(var s in deviceIds){
                  // 编码转换
                  channelModel.updateDeviceInfo(deviceIds[s]).catch((e)=>{
                    logger.error(e);
                  });
                }
                sip.send(sip.makeResponse(rq,200,'OK'));
                break;
              default:
                logger.error('未解析的指令',CmdType);
            }
          }else if(result.Response){
            if(!constants.registry[deviceid]){
              logger.error('未注册成功', deviceid);
              return;
            }

            let CmdType = result.Response.CmdType.toString();
            sip.send(sip.makeResponse(rq,200,'OK'));
            
            if(!constants.registry[deviceid].channels){
              constants.registry[deviceid].channels={};
            }
            // 收到设备列表后回复
            switch(CmdType){
              case "DeviceInfo":
                // 暂未使用
                logger.info('deviceInfo response', result.Response);
  
                let DeviceType = result.Response.DeviceType.toString();
                if(DeviceType=='IPC'){
                  constants.registry[deviceid].sumnum=result.Response.MaxCamera.toString();
                  let temp1=Object.assign({
                    Name:[''],
                    Owner:[''],
                    ParentID : [result.Response.DeviceID.toString()],
                    CivilCode:[''],
                    Address:[''],
                    RegisterWay:['1'],
                    Secrecy:['0']
                  },result.Response);

                  let channelId=temp1.DeviceID.toString();
                  if(!constants.registry[deviceid].channels[channelId]){
                    // 子通道赋初值
                    constants.registry[deviceid].channels[channelId]=Object.assign({},constants.registry[deviceid]);
                    delete constants.registry[deviceid].channels[channelId]['channels'];
                    delete constants.registry[deviceid].channels[channelId]['sip_command_host'];
                    delete constants.registry[deviceid].channels[channelId]['sip_command_port'];

                    constants.registry[deviceid].channels[channelId].deviceid=temp1.DeviceID.toString();
                    if(!constants.registry[deviceid].channels[channelId].uri){
                      logger.warn(constants.registry[deviceid].channels[channelId]);
                    }else{
                      constants.registry[deviceid].channels[channelId].uri=constants.registry[deviceid].channels[channelId].uri.replace(deviceid,channelId);
                    }
                    constants.registry[deviceid].channels[channelId].parentid=deviceid;
                  }

                  channelModel.updateDeviceInfo(temp1);
                }else{
                  // NVR ，发目录查询指令
                  let catalogCmd = command.catalog(constants.registry[deviceid]);
                  if(catalogCmd){
                    sip.send(catalogCmd);
                  }
                }
                break;
              case "Catalog":
                // 通道数量 
                constants.registry[deviceid].sumnum=result.Response.SumNum.toString();

                for(let s in result.Response.DeviceList[0].Item){
                  let temp = result.Response.DeviceList[0].Item[s];
                  if(!temp.DeviceID.toString()){
                    continue;
                  }
                  if(temp.Name.toString()){
                    let bufs = iconv.decode(temp.Name.toString(), 'gb2312');
                    //转为utf8
                    temp.Name = [bufs.toString('utf8')];
                  }

                  let channelId=temp.DeviceID.toString();
                  if(!constants.registry[deviceid].channels[channelId]){
                    // 子通道赋初值
                    constants.registry[deviceid].channels[channelId]=Object.assign({},constants.registry[deviceid]);
                    delete constants.registry[deviceid].channels[channelId]['channels'];
                    delete constants.registry[deviceid].channels[channelId]['sip_command_host'];
                    delete constants.registry[deviceid].channels[channelId]['sip_command_port'];

                    constants.registry[deviceid].channels[channelId].deviceid=temp.DeviceID.toString();
                    if(!constants.registry[deviceid].channels[channelId].uri){
                      logger.warn(constants.registry[deviceid].channels[channelId]);
                    }else{
                      constants.registry[deviceid].channels[channelId].uri=constants.registry[deviceid].channels[channelId].uri.replace(deviceid,channelId);
                    }
                    constants.registry[deviceid].channels[channelId].parentid=deviceid;
                  }
                  
                  if(!temp.ParentID){
                    temp.ParentID=[deviceid];
                  }
                  channelModel.updateDeviceInfo(temp);
                }
                break;
              default:
                break;
            }
          }
        });
      }
    }
    else if(rq.method=='ACK'){
      logger.info('TODO: ack',rq);
    }
    else if(rq.method=='BYE'){
      let ack = command.byeAck(rq);
      sip.send(ack);
    }
    else {
      logger.debug('TODO:', rq.method);
      sip.send(sip.makeResponse(rq, 405, 'Method Not Allowed'));
    }
  },
  /**
   * 对外接口
   * @param {发邀请目标} target 
   */
  invite:function(deviceid,channel,udpPort,callback){
    this.loadDevice(deviceid,(obj)=>{
      if(obj){
        let cmd = command.invite(deviceid,channel,udpPort);
        if(!cmd){
          callback(false);
        }else{
          sip.send(cmd);
          callback(true);
        }
      }else{
        logger.error('TODO:404 设备不存在');
      }
    });
  },
  bye:function(deviceid,channel,callback){
    this.loadDevice(deviceid,(obj)=>{
      if(obj){
        let cmd = command.bye(deviceid,channel);
        if(!cmd){
          callback(false);
        }else{
          sip.send(cmd);
          callback(true);
        }
      }else{
        logger.error('TODO:404 设备不存在');
      }
    });
  },
  /**
   * 请求设备信息
   * @param {*} deviceid 
   */
  catalog:function(deviceid){
    this.loadDevice(deviceid,(obj)=>{
      if(obj){
        let catalogCmd = command.catalog(constants.registry[deviceid]);
        if(catalogCmd){
          sip.send(catalogCmd);
        }
      }else{
        logger.error('TODO:404 设备不存在');
      }
    });
  }
  
}

module.exports = sipServer;
